package com.mkl.ttxt.pd.service.impl;

import com.alibaba.fastjson.JSON;
import com.google.common.base.Joiner;
import com.mkl.ttxt.common.bo.TtxtResult;
import com.mkl.ttxt.common.constant.BaseConstant;
import com.mkl.ttxt.common.exception.BusinessException;
import com.mkl.ttxt.pd.bo.*;
import com.mkl.ttxt.pd.dao.IPdDao;
import com.mkl.ttxt.pd.service.IPdService;
import com.mkl.ttxt.pd.util.PlanUtil;
import com.mkl.ttxt.pd.util.PlanUtilV2;
import io.netty.util.internal.StringUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;

import static java.util.stream.Collectors.toList;

@Service
@Transactional
public class PdImpl implements IPdService {

    @Autowired
    IPdDao iPdDao;

    @Autowired
    BaseConstant baseConstant;

    @Override
    public void initMemberBox(Integer rank, Integer userId) {
        iPdDao.cleanBox(userId);
        List<MemberOrCard> members = iPdDao.getAllMember(userId);
        List<MemberOrCard> cards = iPdDao.getAllCard();
        for (MemberOrCard member : members) {
            List<Box> boxList = new ArrayList();
            for (MemberOrCard card : cards) {
                Box box = new Box();
                box.setMemberId(member.getId());
                box.setCardId(card.getId());
                box.setRank(rank);
                box.setStar(5);
                boxList.add(box);
            }
            iPdDao.batchInsert(boxList, userId);
        }
    }

    @Override
    public List<MemberOrCard> getMemberBox(Integer userId) {
        List<MemberOrCard> members = iPdDao.getAllMember(userId);
        for (MemberOrCard member : members) {
            member.setBox(iPdDao.getMemberBox(member.getId()));
        }
        return members;
    }

    @Override
    public void updateBox(Box box, Integer userId) {
        iPdDao.updateBox(box, userId);
    }

    @Override
    public void addLineup(Lineup lineup, Integer userId) {
        iPdDao.addLineup(lineup, userId);
    }

    @Override
    public List<Lineup> getAllLineup(Integer userId) {
        List<Lineup> lineupList = iPdDao.getAllLineup(userId);
        for (Lineup item : lineupList) {
            getLineupDetail(item);
        }
        return lineupList;
    }

    @Override
    public List<MemberOrCard> getMember(Integer userId) {
        return iPdDao.getAllMember(userId);
    }

    @Override
    public Object getCard() {
        return iPdDao.getAllCard();
    }

    @Override
    public void calPossibleLineUp(Integer userId) {
        iPdDao.cleanMemberLineup(userId);
        List<MemberOrCard> memberList = getMemberBox(userId);
        List<Lineup> lineupList = getAllLineup(userId);
        for (MemberOrCard member : memberList) {
            //遍历所有人，确认是否能出
            for (Lineup lineup : lineupList) {
                boolean isEnable = checkMemberLineup(member, lineup);
                MemberLineup memberLineup = new MemberLineup();
                memberLineup.setMemberId(member.getId());
                memberLineup.setLineupId(lineup.getId());
                memberLineup.setIsEnable(isEnable);
                iPdDao.recordMemberLineup(memberLineup, userId);
            }
        }
    }

    private boolean checkMemberLineup(MemberOrCard member, Lineup lineup) {
        List<Box> memberBoxList = member.getBox();
        List<LineupCard> lineupCardList = lineup.getLineupCardList();
        Integer deletionCount = 0;
        for (LineupCard lineupCard : lineupCardList) {
            Integer needCardId = lineupCard.getCardId();
            String needCardStar = lineupCard.getStar();
            List<String> needCardStarList = Arrays.asList(needCardStar.split(","));
            boolean hasCard = false;
            for (Box memberBox : memberBoxList) {
                Integer memberCardId = memberBox.getCardId();
                Integer memberCardStar = memberBox.getStar();
                if (memberCardId.equals(needCardId)) {
                    if (needCardStarList.contains(String.valueOf(memberCardStar))) {
                        hasCard = true;
                    }
                    break;
                }
            }
            if(!hasCard){
                deletionCount ++;
            }
            if (deletionCount > 1) {
                return false;
            }
        }
        return true;
    }

    @Override
    public void calPossibleCompose(Integer userId) {
        iPdDao.cleanPossibleCompose(userId);
        List<Lineup> lineupList = getAllLineup(userId);
        for (Lineup lineup1 : lineupList) {
            List<Integer> lineup1CardIdList = getCardId(lineup1.getLineupCardList());
            for (Lineup lineup2 : lineupList) {
                if (lineup2.getId() <= lineup1.getId()) {
                    continue;
                }
                List<Integer> lineup2CardIdList = getCardId(lineup2.getLineupCardList());
                for (Lineup lineup3 : lineupList) {
                    if (lineup3.getId() <= lineup2.getId()) {
                        continue;
                    }
                    List<Integer> lineup3CardIdList = getCardId(lineup3.getLineupCardList());
                    Set<Integer> total = new HashSet<>();
                    total.addAll(lineup1CardIdList);
                    total.addAll(lineup2CardIdList);
                    total.addAll(lineup3CardIdList);
                    //肯定自己用12张卡
                    if (total.size() >= 12) {
                        //两两不重复2张以上
                        Set<Integer> lineup12 = new HashSet<>(lineup1CardIdList);
                        lineup12.addAll(lineup2CardIdList);
                        Set<Integer> lineup13 = new HashSet<>(lineup1CardIdList);
                        lineup13.addAll(lineup3CardIdList);
                        Set<Integer> lineup23 = new HashSet<>(lineup2CardIdList);
                        lineup23.addAll(lineup3CardIdList);
                        if (lineup12.size() >= 8 && lineup13.size() >= 8 && lineup23.size() >= 8) {
                            LineupCompose lineupCompose = new LineupCompose();
                            lineupCompose.setLineup1(lineup1.getId());
                            lineupCompose.setLineup2(lineup2.getId());
                            lineupCompose.setLineup3(lineup3.getId());
                            List<Integer> lineuo1Members = iPdDao.getMemberIdsByLineup(lineup1.getId(), userId);
                            List<Integer> lineuo2Members = iPdDao.getMemberIdsByLineup(lineup2.getId(), userId);
                            List<Integer> lineuo3Members = iPdDao.getMemberIdsByLineup(lineup3.getId(), userId);
                            List<Integer> intersection12 = lineuo1Members.stream().filter(item -> lineuo2Members.contains(item)).collect(toList());
                            List<Integer> intersection123 = intersection12.stream().filter(item -> lineuo3Members.contains(item)).collect(toList());
                            //检查能不能同时出
                            Iterator<Integer> iterator = intersection123.iterator();
                            while (iterator.hasNext()) {
                                Integer memberId = iterator.next();
                                if(!checkMemberLineupCompose(memberId, lineup1.getLineupCardList(),
                                        lineup2.getLineupCardList(), lineup3.getLineupCardList())){
                                    //移除该人
                                    iterator.remove();
                                }
                            }
                            lineupCompose.setMemberIds(Joiner.on(",").join(intersection123));
                            iPdDao.recordLineupCompose(lineupCompose, userId);
                        }
                    }
                }
            }
        }

        this.calComposeScore(userId,null,null);
    }

    private boolean checkMemberLineupCompose(Integer memberId, List<LineupCard> lineupCardList1, List<LineupCard> lineupCardList2, List<LineupCard> lineupCardList3) {
        List<Box> boxList = iPdDao.getMemberBox(memberId);
        List<Integer> lineup1CardIdList = getCardId(lineupCardList1);
        List<Integer> lineup2CardIdList = getCardId(lineupCardList2);
        List<Integer> lineup3CardIdList = getCardId(lineupCardList3);
        Set<Integer> total12 = new HashSet<>();
        total12.addAll(lineup1CardIdList);
        total12.addAll(lineup2CardIdList);
        Set<Integer> cardSet12 = new HashSet<>();
        for(Integer cardId : total12){
            for(Box box:boxList){
                if(box.getCardId().equals(cardId)){
                    //检查星级
                    boolean checkFlag = false;
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList1){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet12.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList2){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet12.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                }
            }
        }
        if(cardSet12.size() < 8){
            return false;
        }
        Set<Integer> total23 = new HashSet<>();
        total23.addAll(lineup2CardIdList);
        total23.addAll(lineup3CardIdList);
        Set<Integer> cardSet23 = new HashSet<>();
        for(Integer cardId : total23){
            for(Box box:boxList){
                if(box.getCardId().equals(cardId)){
                    //检查星级
                    boolean checkFlag = false;
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList2){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet23.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList3){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet23.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                }
            }
        }
        if(cardSet23.size() < 8){
            return false;
        }
        Set<Integer> total13 = new HashSet<>();
        total13.addAll(lineup1CardIdList);
        total13.addAll(lineup3CardIdList);
        Set<Integer> cardSet13 = new HashSet<>();
        for(Integer cardId : total13){
            for(Box box:boxList){
                if(box.getCardId().equals(cardId)){
                    //检查星级
                    boolean checkFlag = false;
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList1){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet13.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList3){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet13.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                }
            }
        }
        if(cardSet13.size() < 8){
            return false;
        }

        //两两检查完，三刀检查能不能用自己的12张卡
        Set<Integer> total123 = new HashSet<>();
        total123.addAll(lineup1CardIdList);
        total123.addAll(lineup2CardIdList);
        total123.addAll(lineup3CardIdList);
        Set<Integer> cardSet123 = new HashSet<>();
        for(Integer cardId : total123){
            for(Box box:boxList){
                if(box.getCardId().equals(cardId)){
                    //检查星级
                    boolean checkFlag = false;
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList1){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet123.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList2){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet123.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                    if(!checkFlag){
                        for(LineupCard lineupCard: lineupCardList3){
                            if(lineupCard.getCardId().equals(box.getCardId()) &&
                                    lineupCard.getStar().contains(String.valueOf(box.getStar()))){
                                cardSet123.add(box.getCardId());
                                checkFlag = true;
                            }
                        }
                    }
                }
            }
        }
        if(cardSet123.size() < 12){
            return false;
        }
        return true;
    }

    @Override
    public void subMemberCompose(Integer memberId, Integer lineupComposeId, Integer userId) {
        LineupCompose lineupCompose = iPdDao.getLineupComposeById(lineupComposeId, userId);
        List<String> memberIds = new ArrayList<>(Arrays.asList(lineupCompose.getMemberIds().split(",")));

//        memberIds.remove(String.valueOf(memberId));
        Iterator<String> iterator = memberIds.iterator();
        while(iterator.hasNext()) {
            String item = iterator.next();
            if(String.valueOf(memberId).equals(item)) {
                iterator.remove();
            }
        }

        lineupCompose.setMemberIds(Joiner.on(",").join(memberIds));
        iPdDao.updateLineComposeUser(lineupCompose, userId);
    }

    @Override
    public void optimizePossibleCompose(Integer userId, Integer composeNum, Integer difComposeRepeat) {
        //遍历所有人
        List<MemberOrCard> memberList = iPdDao.getAllMember(userId);
        //每个人保留收益率最高的n个组合
        for(MemberOrCard member: memberList){
            //获取这个人的所有阵容组合
            List<LineupCompose> lineupComposeList = iPdDao.getUserSetMeal(member.getId(), userId);
            //取收益率最高的n个组合，若和高收益率的BOSS重复则弃选
            List<LineupCompose> maxScoreCompose = new ArrayList<>();
            List<Integer> maxScoreComposeId = new ArrayList<>();
            for(LineupCompose item: lineupComposeList){

                item.setLineup1Detail(getLineupDetail(iPdDao.getLineupById(item.getLineup1())));
                item.setLineup2Detail(getLineupDetail(iPdDao.getLineupById(item.getLineup2())));
                item.setLineup3Detail(getLineupDetail(iPdDao.getLineupById(item.getLineup3())));
                if(item.getLineup1Detail().getBossNo().equals(item.getLineup2Detail().getBossNo())
                        || item.getLineup3Detail().getBossNo().equals(item.getLineup2Detail().getBossNo())
                        || item.getLineup1Detail().getBossNo().equals(item.getLineup3Detail().getBossNo())){
                    continue;
                }
                //调整保留最高的N个阵容
                Integer composeNumber = BaseConstant.COMPOSE_NUM;
                if(composeNum != null){
                    composeNumber = composeNum;
                }
                if(maxScoreCompose.size() < composeNumber
                        && checkBossRepeat(item, maxScoreCompose, difComposeRepeat)){
                    //允许重复
//                if(maxScoreCompose.size() < composeNumber){
                    maxScoreCompose.add(item);
                    maxScoreComposeId.add(item.getId());
                }
            }
            //去除这三个组合外的选择
            for(LineupCompose item: lineupComposeList){
                if(!maxScoreComposeId.contains(item.getId())){
                    this.subMemberCompose(member.getId(), item.getId(), userId);
                }
            }
        }
    }

    @Override
    public void calComposeScore(Integer userId, Integer composeNum, Integer difComposeRepeat) {
        //遍历所有阵容组合，计算该组合收益
        baseConstant.loadScoreParam(userId);
        List<LineupCompose> allLineupComposeList = iPdDao.getAllSetMeal(userId);
        for(LineupCompose item: allLineupComposeList){
            if(StringUtil.isNullOrEmpty(item.getMemberIds())){
                continue;
            }
            Lineup lineup1 = getLineupDetail(iPdDao.getLineupById(item.getLineup1()));
            Lineup lineup2 = getLineupDetail(iPdDao.getLineupById(item.getLineup2()));
            Lineup lineup3 = getLineupDetail(iPdDao.getLineupById(item.getLineup3()));

            Integer score1 = getScore(lineup1);
            Integer score2 = getScore(lineup2);
            Integer score3 = getScore(lineup3);

            Integer sum = score1 + score2 + score3;
            iPdDao.recordLineupComposeScore(item.getId(), sum, userId);
        }
    }

    @Override
    public TtxtResult calResultV2(List<Target> targetList, Integer userId) throws Exception {
        //贪心算法版本（全选，优先选可用组合少的）
        //取得分最高的组合，打到不能用为止，找下一个组合，继续打到不能用为止

        //检查所有人是否都能出刀
        checkMemmberResult(userId);

        //估算大概会里成员的组合数，过多给提示并终止
        Integer abandonmentCount = iPdDao.getabandonmentComposeCount(userId);
//        if(abandonmentCount == null || abandonmentCount < 1){
//            throw new BusinessException("组合数过多，请先优化");
//        }

        //规划
        return PlanUtilV2.planning(targetList, userId);
    }

    @Override
    public void calResultV3(List<Target> targetList, Integer userId) {
        //查找已出记录
        //根据已出记录，固定（减少）已出刀人员组合，并标记为已出
    }

    private boolean checkBossRepeat(LineupCompose item, List<LineupCompose> maxScoreCompose, Integer difComposeRepeat) {
        Integer todoBossNo1 = item.getLineup1Detail().getBossNo();
        Integer todoBossNo2 = item.getLineup2Detail().getBossNo();
        Integer todoBossNo3 = item.getLineup3Detail().getBossNo();
        for(LineupCompose lineupCompose: maxScoreCompose){
            Integer doneBossNo1 = lineupCompose.getLineup1Detail().getBossNo();
            Integer doneBossNo2 = lineupCompose.getLineup2Detail().getBossNo();
            Integer doneBossNo3 = lineupCompose.getLineup3Detail().getBossNo();
            if(doneBossNo1.equals(doneBossNo2) || doneBossNo3.equals(doneBossNo2) || doneBossNo1.equals(doneBossNo3)){
                return false;
            }

            List<Integer> doneBossNoList = new ArrayList<>();
            doneBossNoList.add(doneBossNo1);
            doneBossNoList.add(doneBossNo2);
            doneBossNoList.add(doneBossNo3);
            doneBossNoList.remove(todoBossNo1);
            doneBossNoList.remove(todoBossNo2);
            doneBossNoList.remove(todoBossNo3);
            Integer difComposeRepeatNum = BaseConstant.DIF_COMPOSE_REPEAT;
            if(difComposeRepeat != null){
                difComposeRepeatNum = difComposeRepeat;
            }
            if(doneBossNoList == null || doneBossNoList.size() < difComposeRepeatNum){
                return false;
            }
        }
        return true;
    }

    private Integer getScore(Lineup lineup) {
        Integer score = lineup.getDamage();
        if(lineup.getBossNo() == 11){
            score = score * baseConstant.MAGNIFICATION_11;
        }else if(lineup.getBossNo() == 12){
            score = score * baseConstant.MAGNIFICATION_12;
        }else if(lineup.getBossNo() == 13){
            score = score * baseConstant.MAGNIFICATION_13;
        }else if(lineup.getBossNo() == 14){
            score = score * baseConstant.MAGNIFICATION_14;
        }else if(lineup.getBossNo() == 15){
            score = score * baseConstant.MAGNIFICATION_15;
        }else if(lineup.getBossNo() == 16){
            score = score * baseConstant.MAGNIFICATION_16;
        }else if(lineup.getBossNo() == 21){
            score = score * baseConstant.MAGNIFICATION_21;
        }else if(lineup.getBossNo() == 22){
            score = score * baseConstant.MAGNIFICATION_22;
        }else if(lineup.getBossNo() == 23){
            score = score * baseConstant.MAGNIFICATION_23;
        }else if(lineup.getBossNo() == 24){
            score = score * baseConstant.MAGNIFICATION_24;
        }else if(lineup.getBossNo() == 25){
            score = score * baseConstant.MAGNIFICATION_25;
        }else if(lineup.getBossNo() == 26){
            score = score * baseConstant.MAGNIFICATION_26;
        }else if(lineup.getBossNo() == 31){
            score = score * baseConstant.MAGNIFICATION_31;
        }else if(lineup.getBossNo() == 32){
            score = score * baseConstant.MAGNIFICATION_32;
        }else if(lineup.getBossNo() == 33){
            score = score * baseConstant.MAGNIFICATION_33;
        }else if(lineup.getBossNo() == 34){
            score = score * baseConstant.MAGNIFICATION_34;
        }else if(lineup.getBossNo() == 35){
            score = score * baseConstant.MAGNIFICATION_35;
        }else if(lineup.getBossNo() == 36){
            score = score * baseConstant.MAGNIFICATION_36;
        }
        return score;
    }

    @Override
    public Object getAllSetMeal(Integer userId) {
        List<LineupCompose> lineupComposeList = iPdDao.getAllSetMeal(userId);
        for (LineupCompose lineupCompose : lineupComposeList) {
            lineupCompose.setLineup1Detail(getLineupDetail(iPdDao.getLineupById(lineupCompose.getLineup1())));
            lineupCompose.setLineup2Detail(getLineupDetail(iPdDao.getLineupById(lineupCompose.getLineup2())));
            lineupCompose.setLineup3Detail(getLineupDetail(iPdDao.getLineupById(lineupCompose.getLineup3())));
            List<String> memberList = Arrays.asList(lineupCompose.getMemberIds().split(","));
            lineupCompose.setMemberNames(iPdDao.getMembersByIds(memberList));
        }
        return lineupComposeList;
    }

    @Override
    public Object getUserSetMeal(String memberName, Integer userId) {
        Integer memberId = iPdDao.getUserIdByName(memberName, userId);
        List<LineupCompose> lineupComposeList = iPdDao.getUserSetMeal(memberId, userId);
        for (LineupCompose lineupCompose : lineupComposeList) {
            lineupCompose.setLineup1Detail(getLineupDetail(iPdDao.getLineupById(lineupCompose.getLineup1())));
            lineupCompose.setLineup2Detail(getLineupDetail(iPdDao.getLineupById(lineupCompose.getLineup2())));
            lineupCompose.setLineup3Detail(getLineupDetail(iPdDao.getLineupById(lineupCompose.getLineup3())));
            lineupCompose.setMemberIds(null);
            lineupCompose.setMemberId(memberId);
            lineupCompose.setMemberNames(Collections.singletonList(memberName));
        }
        return lineupComposeList;
    }

    @Override
    public void calResult(List<Target> targetList, Integer userId) throws Exception {
        //检查所有人是否都能出刀
        checkMemmberResult(userId);
        //规划
        PlanUtil.planning(targetList, userId);
    }

    private void checkMemmberResult(Integer userId) {
        List<MemberOrCard> memberList = iPdDao.getAllMember(userId);
        List<String> errorMemberNameList = new ArrayList<>();
        for(MemberOrCard member: memberList){
            List<LineupCompose> lineupComposeList = iPdDao.getUserSetMeal(member.getId(), userId);
            if(lineupComposeList == null || lineupComposeList.size() < 1){
                errorMemberNameList.add(member.getName());
            }
        }
        if(errorMemberNameList != null && errorMemberNameList.size() > 0){
            throw new BusinessException("下列成员无法出刀：" + errorMemberNameList);
        }
    }

    private Lineup getLineupDetail(Lineup lineup) {
        List<LineupCard> cardList = JSON.parseArray(lineup.getLineup(), LineupCard.class);
        if(cardList == null || cardList.size() < 1){
            lineup.setLineup(null);
            return lineup;
        }
        for (LineupCard card : cardList) {
            card.setCardName(iPdDao.getCardName(card.getCardId()));
        }
        lineup.setLineup(null);
        lineup.setLineupCardList(cardList);
        return lineup;
    }

    private List<Integer> getCardId(List<LineupCard> lineupCardList) {
        List<Integer> result = new ArrayList<>();
        for(LineupCard lineupCard: lineupCardList){
            result.add(lineupCard.getCardId());
        }
        return result;
    }
}
